use crate::ast::*;
use crate::error::{CompilerError, Result};
use inkwell::values::BasicValueEnum;
use inkwell::AddressSpace;

use super::super::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {
    /// Generate literal value
    pub(in crate::llvm_backend) fn generate_literal(
        &self,
        lit: &Literal,
    ) -> Result<BasicValueEnum<'ctx>> {
        match lit {
            Literal::Integer(i) => {
                // Default to i64 (int) for integer literals, matching type inference behavior
                // Cast to u64 to get the correct bit pattern for negative numbers
                Ok(self.context.i64_type().const_int(*i as u64, false).into())
            }
            Literal::Float(f) => Ok(self.context.f64_type().const_float(*f).into()),
            Literal::String(s) => {
                // 处理转义字符
                let processed_string = s
                    .replace("\\n", "\n")
                    .replace("\\t", "\t")
                    .replace("\\r", "\r")
                    .replace("\\\\", "\\")
                    .replace("\\\"", "\"");

                // Create global string constant with null terminator
                let string_bytes = processed_string.as_bytes();
                let string_type = self
                    .context
                    .i8_type()
                    .array_type(string_bytes.len() as u32 + 1);
                let string_value = self.context.const_string(string_bytes, true); // true = null terminated
                let global_string = self.module.add_global(string_type, None, "str");
                global_string.set_initializer(&string_value);
                global_string.set_constant(true);
                Ok(global_string.as_pointer_value().into())
            }
            Literal::Boolean(b) => Ok(self.context.bool_type().const_int(*b as u64, false).into()),
            Literal::Char(c) => {
                let code_point = *c as u32;
                if code_point > u8::MAX as u32 {
                    return Err(CompilerError::internal(
                        "Char literal out of range (must be within 0-255)",
                    ));
                }
                Ok(self
                    .context
                    .i8_type()
                    .const_int(code_point as u64, false)
                    .into())
            }
            Literal::Null => Ok(self
                .context
                .i8_type()
                .ptr_type(AddressSpace::default())
                .const_null()
                .into()),
        }
    }
}
